package com.k8.common.util;

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SynDoublyLinkedList<T> {
    ReadWriteLock readWriteLock = new ReentrantReadWriteLock();


    private DoublyLinkedList.Node<T> head;
    private DoublyLinkedList.Node<T> tail;
    private int size;

    public SynDoublyLinkedList() {
        head = null;
        tail = null;
        size = 0;
    }


    public DoublyLinkedList.Node<T> addLast(T value) {
        DoublyLinkedList.Node<T> newNode = new DoublyLinkedList.Node<>(value);
        try {
            readWriteLock.writeLock().lock();
            if (tail == null) {
                head = newNode;
            } else {
                tail.next = newNode;
                newNode.prev = tail;
            }
            tail = newNode;
            size++;
        } finally {
            readWriteLock.writeLock().unlock();
        }
        return newNode;
    }


    public DoublyLinkedList.Node<T> addFirst(T value) {
        DoublyLinkedList.Node<T> newNode = new DoublyLinkedList.Node<>(value);
        try {
            readWriteLock.writeLock().lock();
            if (head == null) {
                head = newNode;
                tail = newNode;
            } else {
                newNode.next = head;
                head.prev = newNode;
                head = newNode;
            }
            size++;
        } finally {
            readWriteLock.writeLock().unlock();
        }
        return newNode;
    }

    public DoublyLinkedList.Node<T> poll() {
        try {
            readWriteLock.writeLock().lock();
            if (head == null) return null;
            else if (head == tail) {
                DoublyLinkedList.Node<T> tNode = head;
                head = null;
                tail = null;
                size = 0;
                return tNode;
            } else {
                DoublyLinkedList.Node<T> tNode = head;
                head = head.next;
                size--;
                return tNode;
            }
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }

    public void remove(DoublyLinkedList.Node<T> node) {
        if (node == null) return;
        try {
            readWriteLock.writeLock().lock();
            if (node.prev != null) {
                node.prev.next = node.next;
            } else {
                head = node.next;
            }
            if (node.next != null) {
                node.next.prev = node.prev;
            } else {
                tail = node.prev;
            }
            size--;
        } finally {
            readWriteLock.writeLock().unlock();
        }
    }


    public void printList() {
        DoublyLinkedList.Node<T> current = head;
        while (current != null) {
            System.out.print(current.getValue() + " ");
            current = current.next;
        }
        System.out.println();
    }


    public DoublyLinkedList.Node<T> getNodeAt(int index) {
        try {
            readWriteLock.readLock().lock();
            if (index < 0 || index >= size) return null;
            DoublyLinkedList.Node<T> current = head;
            for (int i = 0; i < index; i++) {
                current = current.next;
            }
            return current;
        } finally {
            readWriteLock.readLock().unlock();
        }
    }

    public int size() {
        try {
            readWriteLock.readLock().lock();
            return size;
        } finally {
            readWriteLock.readLock().unlock();
        }
    }
}
